﻿using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using MultiThumbnail.Properties;
using Timer = System.Windows.Forms.Timer;

namespace MultiThumbnail.Converters.Html
{
    public class HtmlCapture:IDisposable
    {
        private readonly ConverterSettings _settings;
        private readonly string _resultPath;

        private const string StartupPage = "about:blank";
        private readonly Timer _treadyTimer;
        private readonly WebBrowser _web;
        private Size? _imgsize;
        private Rectangle _screen;
        private bool _processing;

        public HtmlCapture(ConverterSettings settings, string resultPath)
        {
            if (settings == null) throw new ArgumentNullException("settings");
            if (resultPath == null) throw new ArgumentNullException("resultPath");
            _settings = settings;
            _resultPath = resultPath;
            _web = new WebBrowser();
            _treadyTimer = new Timer { Interval = 2000 };
            _screen = Screen.PrimaryScreen.Bounds;
            _web.Width = _screen.Width;
            _web.Height = _screen.Height;
            _web.ScriptErrorsSuppressed = true;
            _web.ScrollBarsEnabled = false;
            _web.Navigating += WebNavigating;
            _web.DocumentCompleted += WebDocumentCompleted;
            _imgsize = settings.ImageSize;
            _treadyTimer.Tick += TreadyTimerTick;
        }

        #region Public methods

        private string _startupHtml;

        public void Create(string url)
        {
            _processing = true;
            _imgsize = null;
            ThreadPool.QueueUserWorkItem(Navigate, url);
        }

        public void CreateHtml(string html)
        {
            _imgsize = null;
            _startupHtml = html;
            _processing = true;
            _web.Navigated += WebNavigated;
            ThreadPool.QueueUserWorkItem(Navigate, StartupPage);
        }

        private void Navigate(object state)
        {
             _web.Navigate((string)state);
            Application.DoEvents();
        }

        private void WebNavigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (_web.Document != null)
                _web.Document.Write(_startupHtml);
            _treadyTimer.Start();
        }

        //public void Create(string url, Size imageSize)
        //{
        //    _imgsize = imageSize;
        //    _web.Navigate(url);
        //}

        public void WaitTillFinished()
        {
            Application.DoEvents();
            var waiting = 0;
            while (_processing && waiting < Settings.Default.HtmlLoadTimeout)
            {
                Application.DoEvents();
                waiting += 50;
                Thread.Sleep(50);
            }
        }

        #endregion

        #region Events

        private void WebDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            _treadyTimer.Start();
        }

        private void WebNavigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            _treadyTimer.Stop();
        }

        private void TreadyTimerTick(object sender, EventArgs e)
        {
            if (_web.Document == null || _web.Document.Body == null)
                return;
            _treadyTimer.Stop();
            try
            {
                SaveImage();
            }
            finally
            {
                _processing = false;
            }
        }

        private void SaveImage()
        {
            if (_web.Document == null)
                throw new InvalidOperationException("The Web Document is null");
            if (_web.Document.Body == null)
                throw new InvalidOperationException("The Web Document.Body is null");

            Rectangle body = _web.Document.Body.ScrollRectangle;

            //check if the document width/height is greater than screen width/height
            var docRectangle = new Rectangle
                                   {
                                       Location = new Point(0, 0),
                                       Size = new Size(body.Width > _screen.Width ? _screen.Width : body.Width,
                                                       body.Height > _screen.Height ? _screen.Height : body.Height)
                                   };
            //set the width and height of the WebBrowser object
            _web.Width = docRectangle.Width;
            _web.Height = docRectangle.Height;

            //if the imgsize is null, the imageSize of the image will 
            //be the same as the imageSize of webbrowser object
            //otherwise  set the image imageSize to imgsize
            Rectangle imgRectangle = _imgsize == null ? docRectangle : new Rectangle {Location = new Point(0, 0), Size = _imgsize.Value};

            using (var bitmap = new Bitmap(imgRectangle.Width, imgRectangle.Height))
            {
                var ivo = (IViewObject) _web.Document.DomDocument;

                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    IntPtr hdc = g.GetHdc();
                    ivo.Draw(1, -1, IntPtr.Zero, IntPtr.Zero,
                             IntPtr.Zero, hdc, ref imgRectangle,
                             ref docRectangle, IntPtr.Zero, 0);
                    g.ReleaseHdc(hdc);
                }
                _settings.ConvertImageResult(bitmap, _resultPath);
            }
        }

        #endregion

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
             if (_web != null)
                    _web.Dispose();
                if (_treadyTimer != null)
                    _treadyTimer.Dispose();                
            }
        }
    }
}